package book

import (
	"NovelBook/dao"
	"NovelBook/models/db_models"
	"context"
	"errors"
	"math"
	"strings"
	"time"

	"gorm.io/gorm"
)

func ReturnBooksByUniqueID(req []struct {
	Fine         int64  `json:"fine" binding:"required"`
	BookUniqueID string `json:"book_unique_id" binding:"required"`
}) error {
	var borrowTable []db_models.BorrowTable

	for _, Book := range req {
		parts := strings.SplitN(Book.BookUniqueID, "-", 2)
		var borrowed db_models.BorrowTable

		if err := dao.GetDb().Where("is_returned = false AND return_time <> 0 AND book_id = ? AND books_number_id = ?", parts[0], parts[1]).First(&borrowed).Error; err != nil {
			return err
		}
		if err := dao.GetDb().Where("book_unique_id = ?", Book.BookUniqueID).First(&borrowed.BooksNumber).Error; err != nil {
			return err
		}
		borrowTable = append(borrowTable, borrowed)
		if err := IncFines(Book.Fine); err != nil {
			return err
		}
	}

	borrowerID := borrowTable[0].BorrowerID

	// 调用事务
	if err := ReturnTransaction(borrowerID, borrowTable); err != nil {
		return err
	}

	return nil
}

// ReturnTransaction 归还事务
func ReturnTransaction(borrowerID uint, borrowTables []db_models.BorrowTable) error {
	var BorrowTableID []uint
	var BookUniqueIDs []string

	// 开启事务
	tx := dao.GetDb().Begin()
	if err := tx.Error; err != nil {
		return err
	}

	// 更新书籍库存
	for _, borrowed := range borrowTables {
		BorrowTableID = append(BorrowTableID, borrowed.ID)
		BookUniqueIDs = append(BookUniqueIDs, borrowed.BooksNumber.BookUniqueID)
		if err := tx.Model(&db_models.Books{}).Where("id = ?", borrowed.BookID).UpdateColumn("stock", gorm.Expr("stock + ?", 1)).Error; err != nil {
			tx.Rollback()
			return err
		}
	}

	// 更新用户借阅记录数
	if err := tx.Model(&db_models.Borrower{}).Where("id = ?", borrowerID).UpdateColumn("borrowed", gorm.Expr("borrowed - ?", len(borrowTables))).Error; err != nil {
		tx.Rollback()
		return err
	}

	// 添加归还记录
	if err := tx.Model(&db_models.BorrowTable{}).Where("id IN (?)", BorrowTableID).UpdateColumns(db_models.BorrowTable{IsReturned: true}).Error; err != nil {
		tx.Rollback()
		return err
	}

	// 修改书本状态
	for _, id := range BookUniqueIDs {

		if err := tx.Model(&db_models.BooksNumber{}).Where("book_unique_id = ?", id).UpdateColumn("state", 0).Error; err != nil {
			tx.Rollback()
			return err
		}
	}

	return tx.Commit().Error
}

func IncFines(fines int64) error {
	// 增加redis中的总罚款金额
	ctx := context.Background()

	if _, err := dao.Rdb.IncrBy(ctx, "fines", fines).Result(); err != nil {
		return err
	}
	return nil
}

// 用户先还书，返回每个借阅记录的信息和应付罚款
func ReturnBooksCheck(borrowerID uint, BookUniqueIDs []string) ([]db_models.BorrowFine, error) {
	var fineTable []db_models.BorrowFine
	nowTs := time.Now().UnixNano() / int64(time.Millisecond)

	for _, BookUniqueID := range BookUniqueIDs {
		parts := strings.SplitN(BookUniqueID, "-", 2) // 11-72：书籍id-书籍序号
		var borrowed db_models.BorrowTable
		var m db_models.BorrowFine

		m.BookUniqueID = BookUniqueID

		switch err := dao.GetDb().Where("is_returned = false AND borrower_id = ? AND book_id = ? AND books_number_id = ?", borrowerID, parts[0], parts[1]).First(&borrowed).Error; err != nil {
		case true:
			return nil, err
		}

		switch borrowed.ReturnTime != 0 {
		case true:
			return nil, errors.New("the book has been returned")
		}

		switch err := dao.GetDb().Model(&db_models.BorrowTable{}).Where("id = ?", borrowed.ID).UpdateColumns(db_models.BorrowTable{ReturnTime: nowTs}).Error; err != nil {
		case true:
			return nil, err
		}

		diff := nowTs - borrowed.StartTime
		switch diff > db_models.MaxTime {
		case true:
			Fine := int(math.Ceil(float64(diff) / (1000 * 60 * 60 * 24)))
			m.Fine = Fine
		}
		fineTable = append(fineTable, m)
	}

	switch err := IncBRNumbers(int64(len(BookUniqueIDs))); err != nil {
	case true:
		return nil, err
	}

	return fineTable, nil
}
